﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace PenLiveUpdate {
    public partial class DownloadProgress : Form {
        private bool isFinished = false;
        private AutoUpdater au;
        private List<DownloadFileInfo> downloadFileList = null;
        private ManualResetEvent evtDownload = null;


        public DownloadProgress ( AutoUpdater au, List<DownloadFileInfo> downloadFileList ) {
            InitializeComponent( );

            this.downloadFileList = downloadFileList;
            this.au = au;

        }

        private void OnFormClosing ( object sender, FormClosingEventArgs e ) {
            if (!isFinished && DialogResult.No == MessageBox.Show("当前正在更新，是否取消？", "自动升级", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) {
                e.Cancel = true;
                return;
            }
            
        }

        private void OnFormLoad ( object sender, EventArgs e ) {
            evtDownload = new ManualResetEvent(true);
            evtDownload.Reset( );
            Thread t = new Thread(new ThreadStart(ProcDownload));
            t.Name = "download";
            t.Start( );
            evtDownload.Set( );
        }

        long total = 0;
        long nDownloadedTotal = 0;

        const int C_ReadLen = 640;
        const int C_SyncReadTimeout = 1000;

        private void ProcDownload () {


            foreach (DownloadFileInfo dfile in this.downloadFileList) {
                total += dfile.Size;
            }

            if (this.downloadFileList.Count == 0)
                  Exit(false);


            foreach (DownloadFileInfo dfile in this.downloadFileList) {  //下载列表中的文件

                SetProcessBarMax(dfile.Size, (int)total/100); //设定进度条的最大值

                this.ShowCurrentDownloadFileName(dfile.FileName);

                FileStream aFileStream = null;
                try {
                    HttpWebRequest aRequest = WebRequest.Create(dfile.DownloadUrl ) as HttpWebRequest;
                    aRequest.Credentials = CredentialCache.DefaultCredentials;
                    WebResponse wsp = aRequest.GetResponse( );
                    Stream aStream = wsp.GetResponseStream( );
                    aStream.ReadTimeout = C_SyncReadTimeout;
                    byte[ ] buffer = new byte[C_ReadLen];
                    int offset = 0;
                    int readCnt = 0;
                    string downloadedName = dfile.FileName;//这一行需要修改，要自己起文件名字

                    aFileStream = new FileStream(au.TheFolderPath + @"\" + dfile.FileName, FileMode.Create);//这一行需要修改，要自己起文件名字
                    do {

                        evtDownload.WaitOne();

                        readCnt = aStream.Read(buffer, 0, C_ReadLen);
                        aFileStream.Write(buffer, 0, readCnt);
                        offset += readCnt;
                        nDownloadedTotal += readCnt;

                        SetProcessBar(offset, (int)nDownloadedTotal/100);

                    } while (readCnt > 0);
                    aFileStream.Close( );
                }
                catch (System.Exception) {
                    if (aFileStream != null) {
                        aFileStream.Close( );
                    }
                    MessageBox.Show("服务器或网络错误，请进行检查！");
                    isFinished = true; //由于网络错误，所以认为下载已完成，直接退出，不进行退出提示
                    Exit(false);
                }

                
                   

            }


        Exit(true);

            //Debug.WriteLine("All Downloaded");

        }

        void OnDownloadFileCompleted ( object sender, AsyncCompletedEventArgs e ) {
            DownloadFileInfo file = e.UserState as DownloadFileInfo;
            nDownloadedTotal += file.Size;
            this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
            //Debug.WriteLine(String.Format("Finish Download:{0}", file.FileName));
            //替换现有文件
            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName);
            if (File.Exists(filePath)) {
                if (File.Exists(filePath + ".old"))
                    File.Delete(filePath + ".old");

                File.Move(filePath, filePath + ".old");
            }

            File.Move(filePath + ".tmp", filePath);
            //继续下载其它文件
        }

        void OnDownloadProgressChanged ( object sender, DownloadProgressChangedEventArgs e ) {
            this.SetProcessBar(e.ProgressPercentage, (int)((nDownloadedTotal + e.BytesReceived) * 100 / total));
        }

        delegate void ShowCurrentDownloadFileNameCallBack ( string name );
        private void ShowCurrentDownloadFileName ( string name ) {
            if (this.labelCurrentItem.InvokeRequired) {
                ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);
                this.Invoke(cb, new object[ ] { name });
            } else {
                this.labelCurrentItem.Text = name;
            }
        }

        delegate void SetProcessBarMaxCallBack ( int current, int total );
        private void SetProcessBarMax ( int current, int total ) {
            if (this.progressBarCurrent.InvokeRequired) {
                SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBarMax);
                this.Invoke(cb, new object[ ] { current, total });
            } else {
                if (current == 0)
                {
                    current = 1;
                }
                if (total == 0)
                {
                    total = 1;
                }
                this.progressBarCurrent.Maximum = current;
                this.progressBarTotal.Maximum = total;
            }
        }

        delegate void SetProcessBarCallBack ( int current, int total );
        private void SetProcessBar ( int current, int total ) {
            if (this.progressBarCurrent.InvokeRequired) {
                SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);
                this.Invoke(cb, new object[ ] { current, total });
            } else {
                if (current == 0) {
                    current = 1;
                }
                if (total == 0) {
                    total = 1;
                }
                this.progressBarCurrent.Value = current;
                this.progressBarTotal.Value = total;

                float currentKB, totalKB,ctKB,ttKB;

                currentKB = (float)current / 1024;
                totalKB = (float)this.nDownloadedTotal / 1024;
                ctKB = (float)this.progressBarCurrent.Maximum / 1024;
                ttKB = (float)this.total / 1024;

                lblCurrentByte.Text = currentKB.ToString("#0.00") + @"/" + ctKB.ToString("#0.00") + " K";
                lblTotalByte.Text = totalKB.ToString("#0.00") + @"/" + ttKB.ToString("#0.00") + " K";
            }
        }

        delegate void ExitCallBack ( bool success );
        private void Exit ( bool success ) {
            if (this.InvokeRequired) {
                ExitCallBack cb = new ExitCallBack(Exit);
                this.Invoke(cb, new object[ ] { success });
            } else {
                this.isFinished = success;
                this.DialogResult = success ? DialogResult.OK : DialogResult.Cancel;
                this.Close( );
            }
        }

        private void OnCancel ( object sender, EventArgs e ) {
            evtDownload.Reset();
            this.Close( );
        }
    }
}
